package avicit.bdp.dds.api.utils.notebook;

import avicit.bdp.common.utils.SpringApplicationContext;
import avicit.bdp.dds.api.dto.NoteBookDTO;
import avicit.bdp.dds.api.service.NoteBookService;
import avicit.bdp.dds.common.utils.OSUtils;
import avicit.bdp.dds.server.utils.ProcessUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2022-05-23
 * @类说明：NoteBookExecutor
 * @修改记录：
 * @注意事项：
 * @主要功能：NoteBook后台任务管理工具类
 */
public class NoteBookExecuteUtils {
    private static final Logger logger = LoggerFactory.getLogger(NoteBookExecuteUtils.class);

    private static NoteBookExecuteUtils instance = new NoteBookExecuteUtils();

    /**
     * 线程池，管理NoteBook后台线程
     */
    private static ExecutorService workerExecService;

    /**
     * 任务上下文缓存
     */
    private static NoteBookTaskCacheManager noteBookTaskCacheManager;

    /**
     * NoteBook服务
     */
    private static NoteBookService noteBookService;

    /**
     * 私有构造器
     */
    private NoteBookExecuteUtils() {
        workerExecService = Executors.newCachedThreadPool();
        noteBookTaskCacheManager = SpringApplicationContext.getBean(NoteBookTaskCacheManager.class);
        noteBookService = SpringApplicationContext.getBean(NoteBookService.class);
    }

    public static NoteBookExecuteUtils getInstance() {
        return instance;
    }

    /**
     * 对象销毁时关停线程池
     */
    @PreDestroy
    public void destroy() {
        workerExecService.shutdown();
    }

    /**
     * 启动NoteBook后台线程
     * @param noteBook
     */
    public static void startNoteBookSevice(NoteBookDTO noteBook) {
        updateNoteBookStatus(noteBook, 1);
        workerExecService.submit(new NoteBookExecuteThread(noteBook));
    }

    /**
     * 停止NoteBook后台线程
     * @param noteBook
     */
    public static void stopNoteBookSevice(NoteBookDTO noteBook) {
        if (noteBook == null || StringUtils.isEmpty(noteBook.getId())) {
            return;
        }

        // step1:杀死后台进程
        NoteBookTaskContext taskContext = noteBookTaskCacheManager.getByTaskInstanceId(noteBook.getId());
        if (taskContext == null || taskContext.getProcessId() == null) {
            return;
        }
        doKill(taskContext.getProcessId());

        // step2:更新任务状态
        updateNoteBookStatus(noteBook, 0);

        // step3:移除cache缓存
        noteBookTaskCacheManager.removeByTaskInstanceId(noteBook.getId());
    }

    /**
     * 更新NoteBook服务状态
     * @param noteBook
     * @param status
     */
    public static void updateNoteBookStatus(NoteBookDTO noteBook, Integer status) {
        noteBook.setStatus(status);
        noteBookService.updateNoteBook(noteBook);
        noteBookService.saveBaseUrl2Redis(noteBook);
    }

    /**
     * 更新NoteBook服务日志
     * @param noteBook
     * @param logs
     */
    public static void updateNoteBookLog(NoteBookDTO noteBook, List<String> logs) {
        noteBook.setLog(String.join("\n\t", logs));
        noteBookService.updateNoteBook(noteBook);
    }

    /**
     * 杀死Jupyter NoteBook后台进程
     * @param processId
     */
    public static void doKill(Integer processId) {
        if (processId.equals(0)) {
            logger.info("The jupyter notebook task has not been executed and has been cancelled");
            return;
        }

        if (OSUtils.isWindows()) {
            logger.info("Windows kill jupyter notebook process id:{}", processId);
            ProcessUtils.killWindowsPorcess(processId);
        } else {
            String cmd = String.format("sudo kill -9 %s", processId);
            String[] cmds = {"/bin/sh", "-c", cmd};
            logger.info("The jupyter notebook process id: {}, cmd: {}", processId, cmd);
            try {
                String exeResult = OSUtils.exeShell(cmds);
                logger.info("exe result: {}", exeResult);
            } catch (IOException e) {
                logger.error("exe shell error", e);
            }
        }
    }

    /**
     * 获取运行中的NoteBook列表
     * @return
     */
    public static Map<Integer, NoteBookDTO> getRunningBookNoteList() {
        return noteBookService.getRunningBookNoteList();
    }

    /**
     * 根据NoteBook ID获取上下文
     * @param noteBookId
     * @return
     */
    public static NoteBookTaskContext getNoteBookTaskContextById(String noteBookId) {
        return noteBookTaskCacheManager.getByTaskInstanceId(noteBookId);
    }

    /**
     * 缓存NoteBook任务上下文
     * @param noteBookTaskContext
     */
    public static void cacheTaskExecutionContext(NoteBookTaskContext noteBookTaskContext) {
        noteBookTaskCacheManager.cacheTaskExecutionContext(noteBookTaskContext);
    }
}
